#include "msc_mem.h"	   


#if defined   (__CC_ARM)      /* ARM Compiler */
#define ALIGN(x) __align(x)
#elif defined   ( __GNUC__ )   /* GNU Compiler */
#define ALIGN(x) __attribute__((aligned(x)))
#endif


//内存池(32字节对齐)
ALIGN(32) uint8_t mem1base[MEM1_MAX_SIZE];													//内部SRAM内存池
#if defined   (__CC_ARM)      /* ARM Compiler */
ALIGN(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0x10000000)));					//内部CCM内存池
//ALIGN(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((at(0x68000000)));				//外部SRAM内存池
#elif defined   ( __GNUC__ )   /* GNU Compiler */
ALIGN(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((section(".ccmram")));				//内部CCM内存池
//ALIGN(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((section(".ccmram")));			//外部SRAM内存池
#endif

//内存管理表
uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE];													//内部SRAM内存池MAP
#if defined   (__CC_ARM)      /* ARM Compiler */
uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0x10000000+MEM2_MAX_SIZE)));	    //内部CCM内存池MAP
//uint16_t mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0x68000000+MEM3_MAX_SIZE)));	//外部SRAM内存池MAP
#elif defined   ( __GNUC__ )   /* GNU Compiler */
uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((section(".ccmram")));	    //内部CCM内存池MAP
//uint16_t mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((section(".ccmram")));	    //外部SRAM内存池MAP
#endif

//内存管理参数	   
const uint32_t memtblsize[SRAMBANK] = {MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};//,MEM3_ALLOC_TABLE_SIZE};	//内存表大小
const uint32_t memblksize[SRAMBANK] = {MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE};//,MEM3_BLOCK_SIZE};					//内存分块大小
const uint32_t memsize[SRAMBANK] = {MEM1_MAX_SIZE,MEM2_MAX_SIZE};//,MEM3_MAX_SIZE};							    //内存总大小


//内存管理控制器
struct _msc_mem_dev msc_mem_dev =
{
	mscMemInit,						    //内存初始化
	mscMemPerused,						//内存使用率
    {mem1base,mem2base},//mem3base,			//内存池
    {mem1mapbase,mem2mapbase},//mem3mapbase,//内存管理状态表
    {0,0},//0,  		 					//内存管理未就绪
};

/********************************************************
 * 复制内存
 * *des:目的地址
 * *src:源地址
 * n:需要复制的内存长度(字节为单位)
********************************************************/
void mscMemCpy(void *des,void *src,uint32_t n)  
{  
    uint8_t *xdes = des;
	uint8_t *xsrc = src; 
    while(n--) *xdes++ = *xsrc++;  
}
  
/********************************************************
 * 设置内存
 * *s:内存首地址
 * c :要设置的值
 * count:需要设置的内存大小(字节为单位)
********************************************************/
void mscMemSet(void *s,uint8_t c,uint32_t count)  
{  
    uint8_t *xs = (uint8_t *)s;  
    while(count--) *xs++ = c;  
}	
   
/********************************************************
 * 内存管理初始化  
 * memx:所属内存块
********************************************************/
void mscMemInit(uint8_t memx)  
{  
    mscMemSet(msc_mem_dev.memmap[memx], 0,memtblsize[memx] * 2);//内存状态表数据清零  
	mscMemSet(msc_mem_dev.membase[memx],0,memsize[memx]);	    //内存池所有数据清零  
	msc_mem_dev.memrdy[memx] = 1;								//内存管理初始化OK  
} 
 
/********************************************************
 * 获取内存使用率
 * memx:所属内存块
 * 返回值:使用率(0~100)
********************************************************/
uint8_t mscMemPerused(uint8_t memx)  
{  
    uint32_t used=0;  
    uint32_t i;  
    for(i = 0;i < memtblsize[memx];i ++)  
    {  
        if(msc_mem_dev.memmap[memx][i])
            used ++; 
    } 
    return (used * 100)/(memtblsize[memx]);  
}
  
/********************************************************
 * 内存分配(内部调用)
 * memx:所属内存块
 * size:要分配的内存大小(字节)
 * 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 
********************************************************/
uint32_t mscMemMalloc(uint8_t memx,uint32_t size)  
{  
    signed long offset = 0;  
    uint32_t nmemb;	//需要的内存块数  
	uint32_t cmemb = 0;//连续空内存块数
    uint32_t i;  
    if(!msc_mem_dev.memrdy[memx])//未初始化,先执行初始化 
        msc_mem_dev.init(memx);
    if(size == 0) //不需要分配
        return 0XFFFFFFFF;
    nmemb = size/memblksize[memx];  	//获取需要分配的连续内存块数
    if(size % memblksize[memx])
        nmemb ++;  
    for(offset = memtblsize[memx] - 1;offset >= 0;offset --)//搜索整个内存控制区  
    {     
		if(!msc_mem_dev.memmap[memx][offset])
            cmemb ++;//连续空内存块数增加
		else 
            cmemb = 0;								//连续内存块清零
		if(cmemb == nmemb)							//找到了连续nmemb个空内存块
		{
            for(i = 0;i < nmemb;i ++)  					//标注内存块非空 
            {  
                msc_mem_dev.memmap[memx][offset+i] = nmemb;  
            }  
            return (offset*memblksize[memx]);//返回偏移地址  
		}
    }  
    return 0XFFFFFFFF;//未找到符合分配条件的内存块  
} 
 
/********************************************************
 * 释放内存(内部调用) 
 * memx:所属内存块
 * offset:内存地址偏移
 * 返回值:0,释放成功;1,释放失败; 
********************************************************/ 
uint8_t mscMemFree(uint8_t memx,uint32_t offset)  
{  
    int i;  
    if(!msc_mem_dev.memrdy[memx])//未初始化,先执行初始化
	{
		msc_mem_dev.init(memx);    
        return 1;//未初始化  
    }  
    if(offset < memsize[memx])//偏移在内存池内. 
    {  
        int index = offset/memblksize[memx];			//偏移所在内存块号码  
        int nmemb = msc_mem_dev.memmap[memx][index];	//内存块数量
        for(i = 0;i < nmemb;i ++)  						//内存块清零
        {  
            msc_mem_dev.memmap[memx][index+i] = 0;  
        }  
        return 0;  
    }
    else 
        return 2;//偏移超区了.  
} 
 
/********************************************************
 * 释放内存(外部调用) 
 * memx:所属内存块
 * ptr:内存首地址 
********************************************************/
void mscFree(uint8_t memx,void *ptr)  
{  
	uint32_t offset;   
	if(ptr == NULL)
        return;//地址为0.  
 	offset = (uint32_t)ptr - (uint32_t)msc_mem_dev.membase[memx];     
    mscMemFree(memx,offset);	//释放内存      
}
  
/********************************************************
 * 分配内存(外部调用)
 * memx:所属内存块
 * size:内存大小(字节)
 * 返回值:分配到的内存首地址.
********************************************************/
void *mscMalloc(uint8_t memx,uint32_t size)  
{  
    uint32_t offset;   
	offset = mscMemMalloc(memx,size);  	   	 	   
    if(offset == 0XFFFFFFFF)
        return NULL;  
    else 
        return (void*)((uint32_t)msc_mem_dev.membase[memx]+offset);  
}  

/********************************************************
 * 重新分配内存(外部调用)
 * memx:所属内存块
 * *ptr:旧内存首地址
 * size:要分配的内存大小(字节)
 * 返回值:新分配到的内存首地址.
********************************************************/
void *mscRealloc(uint8_t memx,void *ptr,uint32_t size)  
{  
    uint32_t offset;    
    offset = mscMemMalloc(memx,size);   	
    if(offset == 0XFFFFFFFF)
        return NULL;     
    else  
    {  									   
	    mscMemCpy((void*)((uint32_t)msc_mem_dev.membase[memx]+offset),ptr,size);	//拷贝旧内存内容到新内存   
        mscFree(memx,ptr);  											  		    //释放旧内存
        return (void*)((uint32_t)msc_mem_dev.membase[memx]+offset);  				//返回新内存首地址
    }  
}



